// admin/system/service/sys_menu_service.go
package service

import (
	"errors"
	repo "go-admin1/admin/system/dao"
	"go-admin1/admin/system/model"
	constants "go-admin1/internal/common/constant"

	"strings"
)

// SysMenuService 菜单服务接口
type SysMenuService interface {
	Create(menu *model.SysMenu) error
	GetByID(id int64) (*model.SysMenu, error)
	Update(menu *model.SysMenu) error
	Delete(id int64) error
	List(page, pageSize int) ([]*model.SysMenu, int64, error)
	ListAll() ([]*model.SysMenu, error)
	ListByParentID(parentID int64) ([]*model.SysMenu, error)
	ListByRoleID(roleID int64) ([]*model.SysMenu, error)
	GetMenuTreeByUserId(userId int64) []*RouterVo
}

type sysMenuService struct {
	menuDao repo.SysMenuDao
}

func (s sysMenuService) Create(menu *model.SysMenu) error {
	return s.menuDao.Create(menu)
}

func (s sysMenuService) GetByID(id int64) (*model.SysMenu, error) {
	menu, err := s.menuDao.GetByID(id)
	if err != nil {
		return nil, err
	}
	return menu, nil
}

func (s sysMenuService) Update(menu *model.SysMenu) error {
	existingMenu, err := s.menuDao.GetByID(menu.MenuID)
	if err != nil {
		return err
	}
	if existingMenu == nil {
		return errors.New("菜单不存在")
	}

	return s.menuDao.Update(menu)
}

func (s sysMenuService) Delete(id int64) error {
	existingMenu, err := s.menuDao.GetByID(id)
	if err != nil {
		return err
	}
	if existingMenu == nil {
		return errors.New("菜单不存在")
	}

	return s.menuDao.Delete(id)
}

func (s sysMenuService) List(page, pageSize int) ([]*model.SysMenu, int64, error) {
	menus, total, err := s.menuDao.List(page, pageSize)
	if err != nil {
		return nil, 0, err
	}
	return menus, total, nil
}

func (s sysMenuService) ListAll() ([]*model.SysMenu, error) {
	menus, err := s.menuDao.ListAll()
	if err != nil {
		return nil, err
	}
	return menus, nil
}

func (s sysMenuService) ListByParentID(parentID int64) ([]*model.SysMenu, error) {
	menus, err := s.menuDao.ListByParentID(parentID)
	if err != nil {
		return nil, err
	}
	return menus, nil
}

func (s sysMenuService) ListByRoleID(roleID int64) ([]*model.SysMenu, error) {
	menus, err := s.menuDao.ListByRoleID(roleID)
	if err != nil {
		return nil, err
	}
	return menus, nil
}

func (s sysMenuService) GetMenuTreeByUserId(userId int64) []*RouterVo {
	var menus []*model.SysMenu
	if 1 == userId {
		menus = s.menuDao.GetMenuTreeAll()
	} else {
		menus = s.menuDao.GetMenuTreeByUserId(userId)

	}
	menus = getChildPerms(menus, 0)
	return buildMenus(menus)
}

// recursionFn 递归构建菜单树
// list: 菜单列表
// t: 当前菜单节点
func recursionFn(list []*model.SysMenu, t *model.SysMenu) {
	// 获取子节点列表
	childList := getChildList(list, t)
	var children []model.SysMenu
	for _, child := range childList {
		children = append(children, *child)
	}
	t.Children = children
	for _, tChild := range childList {
		if hasChild(list, tChild) {
			recursionFn(list, tChild)
		}
	}
}

// getChildList 获取指定父节点的子节点列表
func getChildList(list []*model.SysMenu, t *model.SysMenu) []*model.SysMenu {
	var childList []*model.SysMenu
	for _, n := range list {
		if n.ParentID == t.MenuID {
			childList = append(childList, n)
		}
	}
	return childList
}

// hasChild 判断节点是否有子节点
func hasChild(list []*model.SysMenu, t *model.SysMenu) bool {
	for _, n := range list {
		if n.ParentID == t.MenuID {
			return true
		}
	}
	return false
}

// getChildPerms 根据父节点的ID获取所有子节点
func getChildPerms(list []*model.SysMenu, parentId int64) []*model.SysMenu {
	var returnList []*model.SysMenu
	for _, t := range list {
		// 根据传入的某个父节点ID,遍历该父节点的所有子节点
		if t.ParentID == parentId {
			recursionFn(list, t)
			returnList = append(returnList, t)
		}
	}
	return returnList
}

// RouterVo 路由配置信息
// RouterVo 路由配置信息
type RouterVo struct {
	// 路由名字
	Name string `json:"name,omitempty"`

	// 路由地址
	Path string `json:"path,omitempty"`

	// 是否隐藏路由，当设置 true 的时候该路由不会再侧边栏出现
	Hidden bool `json:"hidden,omitempty"`

	// 重定向地址，当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
	Redirect string `json:"redirect,omitempty"`

	// 组件地址
	Component string `json:"component,omitempty"`

	// 路由参数：如 {"id": 1, "name": "ry"}
	Query string `json:"query,omitempty"`

	// 当你一个路由下面的 children 声明的路由大于1个时，自动会变成嵌套的模式--如组件页面
	AlwaysShow *bool `json:"alwaysShow,omitempty"`

	// 其他元素
	Meta *MetaVo `json:"meta,omitempty"`

	// 子路由
	Children []*RouterVo `json:"children,omitempty"`
}

// MetaVo 路由显示信息
// MetaVo 路由显示信息
type MetaVo struct {
	// 设置该路由在侧边栏和面包屑中展示的名字
	Title string `json:"title,omitempty"`

	// 设置该路由的图标，对应路径src/assets/icons/svg
	Icon string `json:"icon,omitempty"`

	// 设置为true，则不会被 <keep-alive>缓存
	NoCache bool `json:"noCache,omitempty"`

	// 内链地址（http(s)://开头）
	Link string `json:"link,omitempty"`
}

// buildMenus 构建前端路由所需要的菜单
func buildMenus(menus []*model.SysMenu) []*RouterVo {
	var routers []*RouterVo
	for _, menu := range menus {
		router := &RouterVo{}
		router.Hidden = "1" == menu.Visible
		router.Name = getRouteName(menu)
		router.Path = getRouterPath(menu)
		router.Component = getComponent(menu)
		router.Query = func() string {
			if menu.Query != nil {
				return *menu.Query
			}
			return ""
		}()
		router.Meta = &MetaVo{
			Title:   menu.MenuName,
			Icon:    menu.Icon,
			NoCache: "1" == menu.IsCache,
			Link:    menu.Path,
		}

		cMenus := menu.Children
		if len(cMenus) > 0 && constants.TYPE_DIR == menu.MenuType {
			router.AlwaysShow = &[]bool{true}[0] // 修复 bool 指针问题
			router.Redirect = "noRedirect"

			// 将 []SysMenu 转换为 []*SysMenu
			var childrenPtrs []*model.SysMenu
			for i := range cMenus {
				childrenPtrs = append(childrenPtrs, &cMenus[i])
			}
			router.Children = buildMenus(childrenPtrs)
		} else if isMenuFrame(menu) {
			router.Meta = nil
			childrenList := make([]*RouterVo, 0)
			children := &RouterVo{
				Path: menu.Path,
				Component: func() string {
					if menu.Component != nil {
						return *menu.Component
					}
					return ""
				}(),
				Name: getRouteNameWithNameAndPath(menu.RouteName, menu.Path),
				Meta: &MetaVo{
					Title:   menu.MenuName,
					Icon:    menu.Icon,
					NoCache: "1" == menu.IsCache,
					Link:    menu.Path,
				},
				Query: func() string {
					if menu.Query != nil {
						return *menu.Query
					}
					return ""
				}(),
			}
			childrenList = append(childrenList, children)
			router.Children = childrenList
		} else if 0 == menu.ParentID && isInnerLink(menu) {
			router.Meta = &MetaVo{
				Title: menu.MenuName,
				Icon:  menu.Icon,
			}
			router.Path = "/"
			childrenList := make([]*RouterVo, 0)
			routerPath := innerLinkReplaceEach(menu.Path)
			children := &RouterVo{
				Path:      routerPath,
				Component: constants.INNER_LINK,
				Name:      getRouteNameWithNameAndPath(menu.RouteName, routerPath),
				Meta: &MetaVo{
					Title: menu.MenuName,
					Icon:  menu.Icon,
					Link:  menu.Path,
				},
			}
			childrenList = append(childrenList, children)
			router.Children = childrenList
		}
		routers = append(routers, router)
	}
	return routers
}

// getRouteName 获取路由名称
func getRouteName(menu *model.SysMenu) string {
	// 非外链并且是一级目录（类型为目录）
	if isMenuFrame(menu) {
		return ""
	}
	return getRouteNameWithNameAndPath(menu.RouteName, menu.Path)
}

// getRouteNameWithNameAndPath 获取路由名称，如没有配置路由名称则取路由地址
func getRouteNameWithNameAndPath(name, path string) string {
	var routerName string
	if name != "" {
		routerName = name
	} else {
		routerName = path
	}
	return capitalize(routerName)
}

// getRouterPath 获取路由地址
func getRouterPath(menu *model.SysMenu) string {
	routerPath := menu.Path
	// 内链打开外网方式
	if menu.ParentID != 0 && isInnerLink(menu) {
		routerPath = innerLinkReplaceEach(routerPath)
	}
	// 非外链并且是一级目录（类型为目录）
	if menu.ParentID == 0 && menu.MenuType == constants.TYPE_DIR && menu.IsFrame == constants.NO_FRAME {
		routerPath = "/" + menu.Path
	} else if isMenuFrame(menu) {
		// 非外链并且是一级目录（类型为菜单）
		routerPath = "/"
	}
	return routerPath
}

// getComponent 获取组件信息
func getComponent(menu *model.SysMenu) string {
	component := constants.LAYOUT
	if menu.Component != nil && *menu.Component != "" && !isMenuFrame(menu) {
		component = *menu.Component
	} else if (menu.Component == nil || *menu.Component == "") && menu.ParentID != 0 && isInnerLink(menu) {
		component = constants.INNER_LINK
	} else if (menu.Component == nil || *menu.Component == "") && isParentView(menu) {
		component = constants.PARENT_VIEW
	}
	return component
}

// capitalize 将字符串首字母大写（驼峰格式）
func capitalize(str string) string {
	if str == "" {
		return ""
	}
	// 实现首字母大写逻辑
	runes := []rune(str)
	runes[0] = []rune(strings.ToUpper(string(runes[0])))[0]
	return string(runes)
}

// isMenuFrame 是否为菜单内部跳转
func isMenuFrame(menu *model.SysMenu) bool {
	return menu.ParentID == 0 && menu.MenuType == constants.TYPE_MENU && menu.IsFrame == constants.NO_FRAME
}

// isInnerLink 是否为内链组件
func isInnerLink(menu *model.SysMenu) bool {
	return menu.IsFrame == constants.NO_FRAME && isHttp(menu.Path)
}

// isParentView 是否为parent_view组件
func isParentView(menu *model.SysMenu) bool {
	return menu.ParentID != 0 && menu.MenuType == constants.TYPE_DIR
}

// isHttp 检查路径是否为HTTP链接（需要实现StringUtils.ishttp的功能）
func isHttp(path string) bool {
	// 实现链接检查逻辑
	// 这里是简化版本，实际应检查是否以 http:// 或 https:// 开头
	return len(path) > 0
}

// innerLinkReplaceEach 内链域名特殊字符替换
// 返回替换后的内链域名
func innerLinkReplaceEach(path string) string {
	return strings.NewReplacer(
		constants.HTTP, "",
		constants.HTTPS, "",
		constants.WWW, "",
		".", "/",
		":", "/",
	).Replace(path)
}

// NewSysMenuService 创建菜单服务实例
func NewSysMenuService() SysMenuService {
	return &sysMenuService{
		menuDao: repo.NewSysMenuDao(),
	}
}
